package com.zh.test.ProxyAndAspect.filterAspect;

import com.alibaba.fastjson.JSON;
import com.zh.test.bean.OutJson;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author zh
 * @Description  对 checkefilter进行AOP植入  https://www.cnblogs.com/timeflying/p/11523314.html
 * @Date 2020/9/4
 * @Param
 * @return
 **/
@Component
@Aspect
public class filterAspectAOP {

    @Pointcut("@annotation(com.zh.test.ProxyAndAspect.filterAspect.CheckFilter)")
    public void pointCut(){
    }
    // todo around植入有拦截效果与增强效果
    // todo 如果需要对请求拦截,需要使用环绕
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint){
        /*
            获取当前方法与方法上指定注解
            获取注解里的方法指明的拦截器类型
            反射执行拦截器中doFilter方法去请求进行判断,前置条件的判断是有先后顺序,例:拣货单要下发->车辆未冻结->钥匙为外借->
            判断失败的直接返回errorJson
            判断成功直接执行方法获取返回结果
         */
        Object result = null;
        List<Object> argList = null;
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String requestUrl = request.getRequestURL().toString();

            // 被切方法
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;

            // 方法类型(webservice还是http)


            // 获取post数据
            String[] parameterNames = ((MethodSignature) signature).getParameterNames();
            argList = new ArrayList<>();
            for (Object arg : joinPoint.getArgs()) {
                // request/response无法使用toJSON
                if (arg instanceof HttpServletRequest) {
                    argList.add("request");
                } else if (arg instanceof HttpServletResponse) {
                    argList.add("response");
                } else {
                    argList.add(JSON.toJSON(arg));
                }
            }

            result = joinPoint.proceed();
            result = joinPoint.proceed();
            result = joinPoint.proceed();
            OutJson r = (OutJson)result;
            //耗时
            //请求时间
            LocalDateTime requestTime =LocalDateTime.now();
            //请求次数
            Integer sendNum = 1;
            //uuid
            String uuid = UUID.randomUUID().toString();

            Integer states = 0;

        } catch (Exception e) {
            e.printStackTrace();

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return  result;

    }


    // todo before植入没有拦截效果,只有增强效果
    @Before("pointCut()")
    public void before (JoinPoint joinPoint){
        Method currentMethod = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Object[] args = joinPoint.getArgs();
        CheckFilter annotation = currentMethod.getAnnotation(CheckFilter.class);
        Class[] classes = annotation.filterChain();
        List<Class> collect = Stream.of(classes).collect(Collectors.toList());

        for(int i = 0 ; i<collect.size() ; i++){
           if(!filterHandler(collect.get(i),args)){
               break;
           }
        }
    }

    public boolean filterHandler(Class c,Object... args){
    //todo 只传递一个请求参数是否功能性太低

        try {
            Method doFilter = c.getMethod("doFilter", args.getClass());
            Object o = c.newInstance();
            //普通方法反射执行,需要实例+ 真实参数
            //ReflectUtils
            //获取执行结果,返回值object 可转成任意高阶类
            Boolean b = (Boolean)doFilter.invoke(o,(Object)args);
            return  b;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return false;
    }

}
